//==============================================================================
//
//               Copyright (C) 2005  Dick van Oudheusden
//  
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2007-10-30 21:17:43 $ $Revision: 1.4 $
//
//==============================================================================

#include <stdlib.h>
#include <math.h>

#include "ofc/DIntArray.h"

#include "DInc.h"
#include "DTest.h"


#define sizear(ar)   (sizeof(ar) / sizeof(ar[0]))

//-Datatype--------------------------------------------------------------------

void DIntArray_test(void)
{
  DIntArray *ar1    = [DIntArray alloc];
  DIntArray *ar2    = nil;
  DIntArray *ar3    = [DIntArray new  ];
  DText     *txt    = nil;
  char      *pntr;
  char       test[] = "  -4,  -8  ,34534;12,";
  
  int        ar4[]  = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
  int        ar5[]  = { -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 };
  int        ar6[]  = { 5, 4, 3, 2, 1, 8};
  int        ar7[]  = { 1, 1, 2, 3, 5, 4, 3, 2, 1, 8, 13, 21, 34, 55, 89 }; // ar6 inserted into ar4
  int        ar8[]  = { 1, 1, 2, 3, 5, 4, 3, 55, 89 }; // ar7 deleted from 7 - 12
  int        ar9[]  = { 1,2,3 };
  int        ar10[] = { 4,5 };
  int        ar11[] = { 1,2,4,5};
  int        ar12[] = { 5 };
  int        ar13[] = { 7,8,9 };
  int        ar14[] = { 7,8,9 };
  int        ar15[] = { 8,9,5 }; 
  int        ar16[] = { 3,4,5 };
  int        ar17[] = { -2,-1,0,1,2 };
  int        ar18[] = { -2,-1,0,1,2,3,4,5,4,5 };  
  int        ar19[] = { 7, 64, 9, 6, 45, 3, 45, 23, 8, 51, 2, 14, 45, 37, 67, 23, 23, 45, 17, 73 };
  int        ar20[] = { 7, 64, 9, 6, 45, 23, 23, 67, 37, 45, 14, 2, 51, 8, 23, 45, 3, 45, 17, 73 };
  int        ar21[] = { 1,4,5,2,3 };  
  int        ar22[] = { -4,-8,34534,12 };
  int        ar23[] = { 2,3,6,7,8,9,14,17,23,23,23,37,45,45,45,45,51,64,67,73 };
  int        ar24[] = { 7,64,9,6,2,3,8,14,23,45,45,45,51,37,67,23,23,45,17,73 };
  
  STARTTEST();

  // Init with array
  TEST([ar1 init :ar4 :sizear(ar4)] != nil);
  
  TEST([ar1 length] == sizear(ar4));
  TEST(![ar1 isEmpty]);
  
  // Init by copy
  ar2 = [ar1 copy]; 
  
  TEST([ar2 length] == sizear(ar4));
  
  TEST([ar1 compare :ar2] == 0);

  TEST([ar1 array] != [ar2 array]);

  // Default init
  TEST([ar3 length] == 0);
  TEST([ar3 isEmpty]);
  
  // Clear the array
  TEST([[ar1 clear] length] == 0);
  TEST([ar1 isEmpty]);
  
  // Set the object with an array
  TEST([[ar1 set :ar5 :sizear(ar5)] length] == sizear(ar5));
  
  // Elements in array
  TEST([ar1 get :-1] == 64);
  TEST([[ar1 put :14 :128] get :-1] == 128);
  TEST([[ar1 put :14 :64] length] == sizear(ar5));
  
  TEST([ar1 bcompare :ar5 :sizear(ar5)] == 0);
  
  // Insert & delete elements
  TEST([[ar1 insert :0 :-128] length] == (sizear(ar5)+1));
  TEST([ar1 get :0] == -128); 
  
  TEST([[ar1 insert :-1 :128] length] == (sizear(ar5)+2));
  TEST([ar1 get :-2] == 128);
  
  TEST([[ar1 insert :7 :57] length] == (sizear(ar5)+3));
  TEST([ar1 get :7] == 57); 
  
  [ar1 delete :7];
  [ar1 delete :-2];
  [ar1 delete :0];
  
  TEST([ar1 bcompare :ar5 :sizear(ar5)] == 0);
  
  // Insert & delete slices
  [ar1 set :ar4 :sizear(ar4)]; 
  [ar1 insert :4 :5 :ar6 :sizear(ar6)];
  
  TEST([ar1 bcompare :ar7 :sizear(ar7)] == 0);
  
  [ar1 delete :7 :12];
  
  TEST([ar1 bcompare :ar8 :sizear(ar8)] == 0);
  
  [ar1 set :ar9 :sizear(ar9)];
  [ar1 insert :-1 :-1 :ar10 :sizear(ar10)];
  TEST([ar1 bcompare :ar11 :sizear(ar11)] == 0);  
  
  [ar1 delete :0 :2];

  TEST([ar1 bcompare :ar12 :sizear(ar12)] == 0);  
  
  [ar1 insert :0 :0 :ar13 :sizear(ar13)];
                                    
  TEST([ar1 bcompare :ar14 :sizear(ar14)] == 0); 
                                                         
  
  [ar2 free];
  
  ar2 = [ar1 get :1 :3];
  TEST([ar2 length] == 3);
  
  TEST([ar2 bcompare :ar15 :sizear(ar15)] == 0); 

  [ar1 set :ar9 :sizear(ar9)];
  
  [ar1 insert :1 :0 :ar10 :sizear(ar10)]; 

  TEST([ar1 bcompare :ar21 :sizear(ar21)] == 0);
  
  // Append & prepend
  [ar1 set :ar16 :sizear(ar16)]; 
  
  [ar1 prepend :ar17 :sizear(ar17)]; 
  [ar1 append  :ar10 :sizear(ar10)];
  
  TEST([ar1 bcompare :ar18 :sizear(ar18)] == 0); 
  TEST([ar1 length] == 10);
  
  // LIFO & FIFO
  [ar1 clear];
  
  [ar1 push :3];
  [ar1 push :4];
  TEST([ar1 tos] == 4);
  [ar1 push :5];
  
  TEST([ar1 length] == 3);
  TEST([ar1 bcompare :ar16 :sizear(ar16)] == 0);
  
  TEST([ar1 pop] == 5);
  TEST([ar1 pop] == 4);
  TEST([ar1 tos] == 3);
  TEST([ar1 pop] == 3);
  TEST([ar1 length] == 0);
  TEST([ar1 pop] == 0);
  
  [ar1 clear];

  [ar1 enqueue :5];
  [ar1 enqueue :4];
  [ar1 enqueue :3];
  
  TEST([ar1 length] == 3);
  TEST([ar1 bcompare :ar16 :sizear(ar16)] == 0);
  
  TEST([ar1 dequeue] == 5);
  TEST([ar1 dequeue] == 4);
  TEST([ar1 dequeue] == 3);
  
  TEST([ar1 length] == 0);
  
  TEST([ar1 dequeue] == 0);
  
  // Statistical methods
  [ar1 set :ar19 :sizear(ar19)]; // { 7, 64, 9, 6, 45, 3, 45, 23, 8, 51, 2, 14, 45, 37, 67, 23, 23, 45, 17, 73 };

  TEST([ar1 count :45 :0 :-1] == 4);
  TEST([ar1 count :23 :0 :7 ] == 1);
  
  TEST([ar1 index :45 :0  :-1] == 4);
  TEST([ar1 index :23 :-8 :-1] == 15);
  TEST([ar1 index :-1 :0  :7 ] == -1);
  
  
  TEST([ar1 rindex :45 :0 :-1] == 17);
  TEST([ar1 rindex :45 :0 :8 ] == 6);
  TEST([ar1 rindex :8  :7 :0 ]  == -1);
  
  TEST([ar1 sum :0 :-1] == 607);
  TEST([ar1 sum :4 :17] == 431);
  TEST([ar1 max :0 :-1] == 73);
  TEST([ar1 max :4 :17] == 67);
  TEST([ar1 min :0 :-1] == 2);
  TEST([ar1 min :4 :17] == 2);
  TEST(fabs([ar1 average :0 :-1] - 30.350) < 0.01);
  TEST(fabs([ar1 average :4 :17] - 30.786) < 0.01);
  TEST(fabs([ar1 variance :0 :-1] - 493.828) < 0.01); 
  TEST(fabs([ar1 variance :4 :17] - 367.883) < 0.01);
  TEST(fabs([ar1 standardDeviation :0 :-1] - 22.222) < 0.01);
  TEST(fabs([ar1 standardDeviation :4 :17] -19.180) < 0.01);

  // Invert the array
  [ar1 set :ar19 :sizear(ar19)];
  
  [ar1 invert :4 :17];
  
  TEST([ar1 bcompare :ar20 :sizear(ar20)] == 0);
  
  // text methods
  [ar1 set :ar18 :sizear(ar18)];
  
  txt = [ar1 toText]; 
  
  TEST([txt ccompare :"-2,-1,0,1,2,3,4,5,4,5"] == 0);

  pntr = (char *) [txt cstring];
  
  TEST([ar2 fromString :&pntr] == 0);
  TEST([ar1 compare :ar2] == 0);
  TEST(*pntr == EOS);
  
  pntr = test;
  TEST([ar2 fromString :&pntr] == 0); 
  TEST([ar2 bcompare :ar22 :sizear(ar22)] == 0);
  TEST(*pntr == ',');
  
  [txt free];

  // sorting
  [ar1 set :ar19 :sizear(ar19)];                 // { 7,64,9,6,45,3,45,23,8,51,2,14,45,37,67,23,23,45,17,73 };
  [ar1 sort :0 :-1];
  TEST([ar1 bcompare :ar23 :sizear(ar23)] == 0); // { 2,3,6,7,8,9,14,17,23,23,23,37,45,45,45,45,51,64,67,73 };
  
  [ar1 set :ar19 :sizear(ar19)];
  [ar1 sort :4 :12];
  TEST([ar1 bcompare :ar24 :sizear(ar24)] == 0);
  
  [ar3 free];
  [ar2 free];
  [ar1 free];
  
  STOPTEST();
}

